home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 January: Mac OS SDK / Dev.CD Jan 99 SDK1.toast / Development Kits / Apple Guide / Engineering / APISample / APISampleMPW / Source / UDocMo.cp < prev    next >
Encoding:
Text File  |  1994-07-25  |  28.8 KB  |  1,119 lines  |  [TEXT/MPS ]

  1. // Copyright ©1994 Apple Computer, Inc.
  2. // Author: John Powers
  3. // Date:   25-Jul-94
  4.  
  5. // UDocMo.cp
  6. // This file contains the documents and the objects that go
  7. // into the document window.
  8.  
  9. #ifndef __UDOCMO__
  10.     #include "UDocMo.h"
  11. #endif
  12.  
  13. // Segment
  14.  
  15. #pragma segment Main
  16.  
  17. // ------------------------------------------------------------------------
  18. // TDocArt::DrawProc
  19. // Called by DeviceLoop.
  20. // A static function.  Must be in a resident segment, locked and unpurgeable.
  21. // Because it's static, it cannot access object member variables directly.
  22. // We use the document window passed in userData to access its variables.
  23. pascal void
  24. TDocArt::DrawProc(short depth, short /*deviceFlags*/,
  25.                                         GDHandle hTargetDevice,
  26.                                         long userData)
  27. {
  28.             // Get the document window from userData.
  29.     TDocArt* theDocObject = (TDocArt*) userData;
  30.             // Use depth of 1 if we have a computer without CQD.
  31.     depth = (hTargetDevice==NULL)?1:depth;
  32.             // Draw our objects.
  33.     for(short i=0; i<theDocObject->fArtCnt; i++)
  34.         ((TArt**)(*theDocObject->fhArt))[i]->Draw(depth);
  35. };
  36.  
  37. // Segment
  38.  
  39. #pragma segment MoG1
  40.  
  41. // =========================================================================
  42. // TDocArt : TDoc : TDocument
  43. // ------------------------------------------------------------------------
  44. // TDocArt::TDocArt
  45. // Document window constructor.
  46. // Creates the window contents (TArt objects).
  47. TDocArt::TDocArt(short resID) : TDoc(resID)
  48. {
  49.     this->fArtResId = 0;
  50.     this->fArtCnt = 0;
  51.     this->fIsCollision = false;
  52.     this->fCollisionEvent = 0;
  53.     this->fWantReset = false;
  54.     this->fWantShuffle = false;
  55.     this->fWantCollision = false;
  56.     this->fhArt = nil;
  57. }
  58.  
  59. // ------------------------------------------------------------------------
  60. // TDocArt::~TDocArt
  61. // Document window destructor.
  62. // Deletes the window contents (TArt objects).
  63. TDocArt::~TDocArt()
  64. {
  65.     if(this->fArtCnt)
  66.     {
  67.         for(short i=0; i<this->fArtCnt; i++)
  68.             delete ((TArt**)(*this->fhArt))[i];
  69.         DisposeHandle(this->fhArt);
  70.     }
  71.     if(this->fOffScreen)
  72.     {
  73.         delete this->fOffScreen;
  74.     }
  75. }
  76.  
  77. // ------------------------------------------------------------------------
  78. // TDocArt::DoContent
  79. // The localMouse is in the content portion of the window.
  80. // Check to see if it's on any art objects.
  81. void
  82. TDocArt::DoContent(EventRecord* pEvent)
  83. {
  84.     Rect    drawRect;
  85.     TArt*    artObj;
  86.     Point localMouse = pEvent->where;
  87.     GlobalToLocal(&localMouse);
  88.     for(short i=0; i<this->fArtCnt; i++)
  89.     {
  90.         artObj = ((TArt**)(*this->fhArt))[i];
  91.         artObj->GetDrawRect(&drawRect);
  92.         if(PtInRect(localMouse, &drawRect))
  93.         {
  94.             if(this->IsThisKeyDown(kCommandKey))
  95.             {
  96.                     // Command key down.
  97.                     // Startup the guide topic for this art object.
  98.                 if(gAGuideAvailable)
  99.                 {
  100.                         // Get preset guide database file from app.
  101.                     FSSpec fileSpec;
  102.                     this->fApp->GetFile(fileSpec);
  103.                     if(fileSpec.name[0]>0)
  104.                     {
  105.                         SetCursor(*GetCursor(watchCursor));
  106.                             // Open database.
  107.                         AGRefNum refNum;
  108.                         AlertIfError(AGOpenWithSequence(&fileSpec,
  109.                                             0, nil,
  110.                                             artObj->GetSequenceID(),
  111.                                             &refNum));
  112.                             // Set refNum for app.
  113.                         this->fApp->SetRefNum(refNum);
  114.                         SetCursor(&qd.arrow);
  115.                     }
  116.                 }
  117.             }
  118.             else if(artObj->IsMoveable())
  119.             {
  120.                     // Mouse down in our art and no key, track it.
  121.                 this->DragArt(artObj);
  122.             }
  123.                 // No need to check other art objects.
  124.             break;
  125.         }
  126.     }
  127.     if(this->fIsCollision)
  128.     {
  129.             // There was a collision, send the event if it exists.
  130.         if(gAGuideAvailable && this->fCollisionEvent)
  131.         {
  132.             AGRefNum refNum;
  133.             this->fApp->GetRefNum(refNum);
  134.             AGGeneral(refNum, this->fCollisionEvent);
  135.         }
  136.             // Reset collision flag so that we don't keep sending
  137.             // the event every time we click in the window.
  138.         this->fIsCollision = false;
  139.     }
  140. }
  141.  
  142. // ------------------------------------------------------------------------
  143. // TDocArt::DoIdle
  144. // Do any action required during the idle processing.
  145. //
  146. void
  147. TDocArt::DoIdle()
  148. {
  149.     if(this->fWantReset)
  150.     {
  151.         this->Reset();
  152.         this->fWantReset = false;
  153.     }
  154.     if(this->fWantShuffle)
  155.     {
  156.         this->Shuffle();
  157.         this->fWantShuffle = false;
  158.     }
  159. }
  160.  
  161. // ------------------------------------------------------------------------
  162. // TDocArt::DragArt
  163. // Track the mouseDown by dragging the art object.
  164. // The art object is not allowed to overlap another art object.
  165. void
  166. TDocArt::DragArt(TArt* theArt)
  167. {
  168.     Rect    drawRect;
  169.     Rect    eraseRectV;
  170.     Rect    eraseRectH;
  171.     Point    oldLoc;
  172.     Point    newLoc;
  173.     short    deltaV;
  174.     short    deltaH;
  175.         // Get a starting point for the mouseDown location.
  176.     GetMouse(&oldLoc);
  177.         // We may have been Coach-marked, the mouse-down
  178.         // will erase us along with the Coach mark.
  179.         // Let's refresh ourselves before moving.
  180.     theArt->Draw();
  181.     theArt->GetDrawRect(&drawRect);
  182.         // Save current window "picture" off screen.
  183.     this->DrawOff(theArt);
  184.         // Track mouse.
  185.     do
  186.     {
  187.         GetMouse(&newLoc);
  188.         if(PtInRect(newLoc, &drawRect)
  189.             && (newLoc.v!=oldLoc.v || newLoc.h!=oldLoc.h))
  190.         {
  191.                 // The mouse has moved, move the art.
  192.             deltaV = newLoc.v - oldLoc.v;
  193.             deltaH = newLoc.h - oldLoc.h;
  194.                 // Save the current location.
  195.             eraseRectV = eraseRectH = drawRect;
  196.                 // Proposed rect for art object.
  197.             OffsetRect(&drawRect, deltaH, deltaV);
  198.                 // Cannot go outside of window boundaries
  199.             if(this->IsOutsideWindow(&drawRect))
  200.             {
  201.                     // Set drawRect to current position.
  202.                 theArt->GetDrawRect(&drawRect);
  203.             }
  204.                 // Move if it doesn't overlap with another art object.
  205.             else if(this->IsCollision(theArt, &drawRect))
  206.             {
  207.                     // Oops, a collision; don't move.
  208.                 this->fIsCollision = true;
  209.                     // Set drawRect to current position.
  210.                 theArt->GetDrawRect(&drawRect);
  211.                     // Avoid "springing" effect.
  212.                 oldLoc = newLoc;
  213.             }
  214.             else
  215.             {
  216.                     // No collision, move.
  217.                 this->fIsCollision = false;
  218.                     // Sometimes we move more than one pixel.
  219.                     // Erase the area left behind.
  220.                 if(deltaV>0)
  221.                 {
  222.                         // Moving down.
  223.                     eraseRectV.bottom = eraseRectV.top+deltaV;
  224.                     this->fOffScreen->CopyOffToOn(eraseRectV);
  225.                 }
  226.                 else if(deltaV<0)
  227.                 {
  228.                         // Moving up.
  229.                     eraseRectV.top = eraseRectV.bottom+deltaV;
  230.                     this->fOffScreen->CopyOffToOn(eraseRectV);
  231.                 }
  232.                 if(deltaH>0)
  233.                 {
  234.                         // Moving to the right.
  235.                     eraseRectH.right = eraseRectH.left+deltaH;
  236.                     this->fOffScreen->CopyOffToOn(eraseRectH);
  237.                 }
  238.                 else if(deltaH<0)
  239.                 {
  240.                         // Moving to the left.
  241.                     eraseRectH.left = eraseRectH.right+deltaH;
  242.                     this->fOffScreen->CopyOffToOn(eraseRectH);
  243.                 }
  244.                     // Set new rect and redraw.
  245.                 theArt->SetDrawRect(&drawRect);
  246.                 theArt->Draw();
  247.                 oldLoc = newLoc;
  248.             }
  249.         }
  250.     }
  251.     while (StillDown());
  252. }
  253.  
  254. // ------------------------------------------------------------------------
  255. // TDocArt::Draw
  256. // Document window.
  257. // Within BeginUpdate/EndUpdate.
  258. //
  259. // We set the port because the port defaults to the frontmost window.
  260. // We may not be the frontmost window when the update occurs.
  261. //
  262. void
  263. TDocArt::Draw()
  264. {
  265.             // Setup and do DeviceLoop drawing.
  266.             // Pass the document window in userData.
  267.     long            userData=(long)this;
  268.     DeviceLoopFlags    flags=0;
  269.     SetPort(this->fDocWindow);
  270.     DeviceLoop(this->fDocWindow->visRgn, TDocArt::DrawProc, userData, flags);
  271. };
  272.  
  273. // ------------------------------------------------------------------------
  274. // TDocArt::DrawOff
  275. // Draw window contents to off-screen port.
  276. // Don't draw exceptArt (can be nil).
  277. //
  278. void
  279. TDocArt::DrawOff(TArt* exceptArt)
  280. {
  281.     TArt*    theArt;
  282.             // Prepare off-screen world for drawing.
  283.     this->fOffScreen->PrepareForDrawing();
  284.             // Draw our objects in the off-screen port.
  285.     for(short i=0; i<this->fArtCnt; i++)
  286.     {
  287.         theArt = ((TArt**)(*this->fhArt))[i];
  288.         if(theArt!=exceptArt)
  289.         {
  290.             theArt->Draw();
  291.         }
  292.     }
  293.             // Finished drawing in off-screen world.
  294.     this->fOffScreen->DoneDrawing();
  295. };
  296.  
  297. // ------------------------------------------------------------------------
  298. // TDocArt::GetLocation
  299. // Get the Rect of the named object.
  300. // Return true if the object is found.
  301. //
  302. // If two names, separated by a dash (-), are given,
  303. // the union of the named objects will be returned.
  304. //
  305. Boolean
  306. TDocArt::GetLocation(Ptr pNameIn, Rect* pRect)
  307. {
  308.     Boolean    result=true;
  309.     char    pNameLocal[64];
  310.     Ptr        pName1=pNameLocal;
  311.     Ptr        pName2;
  312.     
  313.             // Split pNameIn into pName1 and pName2.
  314.  
  315.             // Copy first name to pNameLoc (pName1).
  316.     while(*pNameIn && *pNameIn!='-')
  317.         *pName1++ = *pNameIn++;
  318.             // Set terminator for first name at delimiter.
  319.     *pName1 = 0;
  320.             // Reset first name to the beginning.
  321.     pName1 = pNameLocal;
  322.             // If delimiter, then set pName2 to second name.
  323.             // Otherwise, set pName2 to point to null.
  324.     if(*pNameIn)
  325.         pName2 = pNameIn+1;
  326.     else
  327.         pName2 = pNameIn;
  328.  
  329.             // Compare first name with known objects.
  330.  
  331.     char    artName[32];
  332.     Rect    rect1;
  333.     Rect    rect2;
  334.     Boolean    found1=false;
  335.     Boolean    found2=false;
  336.  
  337.     for(short i=0; i<this->fArtCnt; i++)
  338.     {
  339.             // Get the name of the i-th art object.
  340.         ((TArt**)(*this->fhArt))[i]->GetName(artName);
  341.             // See if it matches the first name.
  342.         if(*pName1 && !found1)
  343.         {
  344.             if(isEqualString(pName1, artName))
  345.             {
  346.                 ((TArt**)(*this->fhArt))[i]->GetDrawRect(&rect1);
  347.                 found1 = true;
  348.             }
  349.         }
  350.             // See if it matches the second name.
  351.         if(*pName2 && !found2)
  352.         {
  353.             if(isEqualString(pName2, artName))
  354.             {
  355.                 ((TArt**)(*this->fhArt))[i]->GetDrawRect(&rect2);
  356.                 found2 = true;
  357.             }
  358.         }
  359.     }
  360.             // Form union if both names found.
  361.     if(found1 && found2)
  362.         UnionRect(&rect1, &rect2, pRect);
  363.     else if(found1)
  364.         *pRect = rect1;
  365.     else if(found2)
  366.         *pRect = rect2;
  367.     else
  368.         result = false;
  369.  
  370.     return result;
  371. };
  372.  
  373. // ------------------------------------------------------------------------
  374. // TDocArt::Init
  375. // Document window initialization.
  376. // Creates the window contents (TArt objects).
  377. // The art objects are linked to the window
  378. // by sharing the same resource ID.
  379. // The art object data is set in the LoadArt function.
  380. // We separate the functions so that LoadArt
  381. // can be used for Init and for resetting the objects.
  382. // The window pointer is set in the document initialization.
  383. // Return any error.
  384. //
  385. OSErr
  386. TDocArt::Init(short resID)
  387. {
  388.     OSErr    err=noErr;
  389.     TArt*    artObj;
  390.         // Save our resource id (for resetting.)
  391.     this->fArtResId = resID;
  392.         // Clear our member variables.
  393.     this->fArtCnt = 0;
  394.     this->fhArt = nil;
  395.         // Get the list of art objects.
  396.         // Use local variables for efficiency.
  397.     Handle hArt = GetResource(kResArtObjects, this->fArtResId);
  398.     if(hArt)
  399.     {
  400.             // Better lock this baby down or it will move.
  401.         HLock(hArt);
  402.             // Get the number of art objects.
  403.         ArtListPtr pArtList = (ArtListPtr) *hArt;
  404.         short artCnt = pArtList->artCnt;
  405.             // Get some memory to hold these babies.
  406.         Handle hArtList = NewHandle(artCnt*sizeof(ArtType));
  407.         if(hArtList)
  408.         {
  409.                 // Instantiate each art object and add to list.
  410.             for(short i=0; i<artCnt; i++)
  411.             {
  412.                 artObj = new TArt;
  413.                 ((TArt**)(*hArtList))[i] = artObj;
  414.             }
  415.                 // All okay, update member variables.
  416.             this->fhArt = hArtList;
  417.             this->fArtCnt = artCnt;
  418.                 // Load the art objects.
  419.             this->LoadArt();
  420.         }
  421.         HUnlock(hArt);
  422.     }
  423.     this->fOffScreen = new TBitMapColor;
  424.     if(this->fOffScreen)
  425.         err = this->fOffScreen->Init();
  426.     return err;
  427. }
  428.  
  429. // ------------------------------------------------------------------------
  430. // TDocArt::IsCollision
  431. //
  432. // Tests to see if the proposed rectangle for theArt intersects with any
  433. // of the remaining art objects.  Returns true or false.
  434. // They must be on the same layer to collide.
  435. //
  436. Boolean
  437. TDocArt::IsCollision(TArt* theArt, Rect* proposedArtRect)
  438. {
  439.     Rect    testRect;
  440.     Rect    dstRect;
  441.     TArt*    theOtherArt;
  442.     for(short i=0; i<this->fArtCnt; i++)
  443.     {
  444.         theOtherArt = ((TArt**)(*this->fhArt))[i];
  445.         if(theOtherArt!=theArt)
  446.         {
  447.             if(this->IsSameLayer(theArt, theOtherArt))
  448.             {
  449.                 theOtherArt->GetDrawRect(&testRect);
  450.                 if(SectRect(proposedArtRect, &testRect, &dstRect))
  451.                 {
  452.                     return true;
  453.                 }
  454.             }
  455.         }
  456.     }
  457.     return false;
  458. }
  459.  
  460. // ------------------------------------------------------------------------
  461. // TDocArt::IsOutsideWindow
  462. // Return true if any portion of the art object 
  463. // is outside of the window content area.
  464. //
  465. // Calculate the intersection of the proposedArtRect with the portRect.
  466. // If the proposedArtRect is entirely within the portRect, the
  467. // intersection will be equal to the proposedArtRect.
  468. // 
  469. Boolean
  470. TDocArt::IsOutsideWindow(Rect* proposedArtRect)
  471. {
  472.     Rect insideRect;
  473.     SectRect(proposedArtRect, &this->fDocWindow->portRect, &insideRect);
  474.     return !EqualRect(proposedArtRect, &insideRect);
  475. }
  476.  
  477. // ------------------------------------------------------------------------
  478. // TDocArt::IsSameLayer
  479. // Return true if the art objects are at the same layer.
  480. Boolean
  481. TDocArt::IsSameLayer(TArt* theArt, TArt* theOtherArt)
  482. {
  483.     return theArt->GetLayer()==theOtherArt->GetLayer();
  484. }
  485.  
  486. // ------------------------------------------------------------------------
  487. // TDocArt::Reset
  488. // Reset the window.
  489. // In this case, we erase the window and redraw its contents.
  490. //
  491. void
  492. TDocArt::Reset()
  493. {
  494.     this->Erase();
  495.     this->LoadArt();
  496.     this->Invalidate();
  497. }
  498.  
  499. // ------------------------------------------------------------------------
  500. // TDocArt::LoadArt
  501. // Art object initialization.
  502. // The memory was allocated in the Init function.
  503. // We separate the functions so that LoadArt
  504. // can be used for Init and for resetting the objects.
  505. void
  506. TDocArt::LoadArt()
  507. {
  508.         // Get the list of art objects.
  509.     Handle hArt = GetResource(kResArtObjects, this->fArtResId);
  510.     if(hArt)
  511.     {
  512.             // Better lock this baby down or it will move.
  513.         HLock(hArt);
  514.             // Get the number of art objects.
  515.         ArtListPtr pArtList = (ArtListPtr) *hArt;
  516.             // Instantiate each art object and add to list.
  517.         for(short i=0; i<this->fArtCnt; i++)
  518.         {
  519.             ((TArt**)(*this->fhArt))[i]->Init(pArtList->art[i]);
  520.         }
  521.         HUnlock(hArt);
  522.     }
  523. }
  524.  
  525. // ------------------------------------------------------------------------
  526. // TDocArt::Shuffle
  527. // Shuffle the location of the art objects.
  528. // We do this by swapping each of the objects
  529. // with another object selected at random.
  530. void
  531. TDocArt::Shuffle()
  532. {
  533.     short    randomNum;
  534.     short    iA;
  535.     short    iB;
  536.     TArt*    artA;
  537.     TArt*    artB;
  538.     if(this->fArtCnt<=0)
  539.         return;
  540.             // Use this->LoadArt() to return all art to its normal location.
  541.     this->Erase();
  542.             // Seed random number generator.
  543.     GetDateTime((unsigned long *)&qd.randSeed);
  544.         // Step through each art object.
  545.     for(iA=0; iA<this->fArtCnt; iA++)
  546.     {
  547.         artA = ((TArt**)(*this->fhArt))[iA];
  548.             // Positive index from 0 to this->fArtCnt-1.
  549.         randomNum = Random();
  550.         randomNum = (randomNum<0)?-randomNum:randomNum;
  551.         iB = randomNum/(32767/this->fArtCnt);
  552. #if __DebugShuffle__
  553.         Str255 msgStr;
  554.         NumToString(iB, msgStr);
  555.         if(iB<0)
  556.         {
  557.             pcat(msgStr, "\p is less than 0.");
  558.             DebugStr(msgStr);
  559.             iB = 0;
  560.         }
  561.         else if(iB>=this->fArtCnt)
  562.         {
  563.             Str255 numStr;
  564.             pcat(msgStr, "\p is equal to or greater than ");
  565.             NumToString(this->fArtCnt, numStr);
  566.             pcat(msgStr, numStr);
  567.             DebugStr(msgStr);
  568.             iB = this->fArtCnt-1;
  569.         }
  570. #endif
  571.         artB = ((TArt**)(*this->fhArt))[iB];
  572.         if(artA!=artB)
  573.         {
  574.                 // Swap locations.
  575.             Rect drawRectA;
  576.             Rect drawRectB;
  577.             artA->GetDrawRect(&drawRectA);
  578.             artB->GetDrawRect(&drawRectB);
  579.             artA->SetDrawRect(&drawRectB);
  580.             artB->SetDrawRect(&drawRectA);
  581.         }
  582.     }
  583.             // Let's draw all the art in its new location.
  584.     this->Invalidate();
  585. }
  586.  
  587. // =========================================================================
  588. // TDocFB : TDoc : TDocument
  589. // ------------------------------------------------------------------------
  590. // TDocFB::TDocFB
  591. // Document window constructor.
  592. // This empty constructor passes the resID to TDoc.
  593. //
  594. TDocFB::TDocFB(short resID) : TDoc(resID)
  595. {
  596.     this->fhControl = nil;
  597. }
  598.  
  599. // ------------------------------------------------------------------------
  600. // TDocFB::~TDocFB
  601. // Document window destructor.
  602. //
  603. TDocFB::~TDocFB()
  604. {
  605.     if(this->fhControl!=nil)
  606.         DisposeControl(this->fhControl);
  607. }
  608.  
  609. // ------------------------------------------------------------------------
  610. // TDocFB::DoContent
  611. // The mouseDown is in the content portion of the window.
  612. // Check to see if it's on a control.
  613. //
  614. void
  615. TDocFB::DoContent(EventRecord* pEvent)
  616. {
  617.     ControlHandle    whichControl;
  618.     Point localMouse = pEvent->where;
  619.     GlobalToLocal(&localMouse);
  620.     short partCode = FindControl(localMouse, this->fDocWindow, &whichControl);
  621.     if(partCode!=0)
  622.     {
  623.         if(TrackControl(whichControl, localMouse, nil)==partCode)
  624.         {
  625.                 // The control was controlled.
  626.                 // Startup the preset database.
  627.             if(gAGuideAvailable)
  628.             {
  629.                     // Get preset guide database file from app.
  630.                 FSSpec fileSpec;
  631.                 this->fApp->GetFile(fileSpec);
  632.                 if(fileSpec.name[0]>0)
  633.                 {
  634.                     SetCursor(*GetCursor(watchCursor));
  635.                         // Open database.
  636.                     AGRefNum refNum;
  637.                     AlertIfError(AGOpen(&fileSpec, 0, nil, &refNum));
  638.                         // Set refNum for app.
  639.                     this->fApp->SetRefNum(refNum);
  640.                     SetCursor(&qd.arrow);
  641.                 }
  642.             }
  643.         }
  644.     }
  645. };
  646.  
  647. // ------------------------------------------------------------------------
  648. // TDocFB::Draw
  649. //
  650. // We set the port because the port defaults to the frontmost window.
  651. // We may not be the frontmost window when the update occurs.
  652. //
  653. void
  654. TDocFB::Draw()
  655. {
  656.     Str255 string;
  657.     SetPort(this->fDocWindow);
  658.     TextFont(monaco);
  659.     TextSize(9);
  660.     TextMode(patCopy);
  661.         // Context check
  662.     MoveTo(kLocH, kLocCCV);
  663.     GetIndString(string, kFeedbackStrId, kStrContext);
  664.     DrawString(string);
  665.     GetPen(&this->fLoc[dataCC]);
  666.         // Coach mark
  667.     MoveTo(kLocH, kLocCHV);
  668.     GetIndString(string, kFeedbackStrId, kStrCoach);
  669.     DrawString(string);
  670.     GetPen(&this->fLoc[dataCH]);
  671.         // Event
  672.     MoveTo(kLocH, kLocEVV);
  673.     GetIndString(string, kFeedbackStrId, kStrEvent);
  674.     DrawString(string);
  675.     GetPen(&this->fLoc[dataEV]);
  676.         // Miscellaneous
  677.     MoveTo(kLocH, kLocMSV);
  678.     GetIndString(string, kFeedbackStrId, kStrMisc);
  679.     DrawString(string);
  680.     GetPen(&this->fLoc[dataTP]);
  681.         // Control
  682.     DrawControls(this->fDocWindow);
  683. }
  684.  
  685. // ------------------------------------------------------------------------
  686. // TDocFB::DrawData
  687. //
  688. // We set the port because the port defaults to the frontmost window.
  689. // We may not be the frontmost window when the update occurs.
  690. //
  691. // The IM QuickDraw documentation is not clear on whether to
  692. // use PenMode or TextMode.  We are passing patCopy to draw
  693. // and patBic to erase in a TextMode procedure, not srcOr and srcBic
  694. // as the documentation would lead you to believe.  Nor does the
  695. // use of patCopy and patBic with PenMode work. Our usage works.
  696. //
  697. void
  698. TDocFB::DrawData(Str255 string, short mode, short whichData)
  699. {
  700.     SetPort(this->fDocWindow);
  701.     TextMode(mode);
  702.     MoveTo(this->fLoc[whichData].h, this->fLoc[whichData].v);
  703.     DrawString(string);
  704. }
  705.  
  706. // ------------------------------------------------------------------------
  707. // TDocFB::Init
  708. //
  709. OSErr
  710. TDocFB::Init()
  711. {
  712.     OSErr err=noErr;
  713.     this->fhControl = GetNewControl(kAssistantCntlID, this->fDocWindow);
  714.     if(this->fhControl)
  715.     {
  716.             // Center control.
  717.         short winWidth = this->fDocWindow->portRect.right
  718.                             - this->fDocWindow->portRect.left;
  719.         short ctrlWidth = (**this->fhControl).contrlRect.right
  720.                             - (**this->fhControl).contrlRect.left;
  721.         short ctrlLeft = (winWidth - ctrlWidth) / 2;
  722.         MoveControl(this->fhControl, ctrlLeft, kLocCTV);
  723.         ShowControl(this->fhControl);
  724.     }
  725.     else
  726.         err = kErrDocFBInitFailed;
  727.     return err;
  728. };
  729.  
  730. // =========================================================================
  731. // TArt
  732. // ------------------------------------------------------------------------
  733. // TArt::Draw
  734. // All art objects (PICT's) are drawn from here.
  735. // This is where we distinguish between B&W and color renderings
  736. // of TArt objects.  The B&W rendering has a resource ID that
  737. // is kBWOffset larger than its color counterpart.
  738. // If the function can't find one version, it will try the other.
  739. void
  740. TArt::Draw(short depth)
  741. {
  742.             // Don't draw empty art.
  743.     if(this->fArt.pictId==0)
  744.         return;
  745.     this->fLastDepth = depth;
  746.     PicHandle    hPict;
  747.     if(depth<8)
  748.     {
  749.             // Use B&W PICT.
  750.         hPict = (PicHandle) GetResource('PICT', this->fArt.pictId+kBWOffset);
  751.         if(!hPict)
  752.         {
  753.                 // No B&W PICT, try color (may really be B&W).
  754.             hPict = (PicHandle) GetResource('PICT', this->fArt.pictId);
  755.         }
  756.     }
  757.     else
  758.     {
  759.             // Use color PICT.
  760.         hPict = (PicHandle) GetResource('PICT', this->fArt.pictId);
  761.         if(!hPict)
  762.         {
  763.                 // No color PICT, try B&W.
  764.             hPict = (PicHandle) GetResource('PICT', this->fArt.pictId+kBWOffset);
  765.         }
  766.     }
  767.     if(hPict)
  768.     {
  769.             // We could have used the fDrawRect private member variable,
  770.             // but we'll use the access function here.
  771.         Rect theDrawRect;
  772.         this->GetDrawRect(&theDrawRect);
  773.         HLock((Handle) hPict);
  774.         DrawPicture(hPict, &theDrawRect);
  775.         HUnlock((Handle) hPict);
  776.     }
  777. };
  778.  
  779. // ------------------------------------------------------------------------
  780. // TArt::Draw
  781. // Draw at the depth used for the last call.
  782. void
  783. TArt::Draw()
  784. {
  785.     this->Draw(this->fLastDepth);
  786. }
  787.  
  788. // ------------------------------------------------------------------------
  789. void
  790. TArt::GetDrawRect(Rect* theRect)
  791. {
  792.     *theRect = this->fDrawRect;
  793. }
  794.  
  795. // ------------------------------------------------------------------------
  796. // TArt::GetName
  797. // Return the name of the art object by copying it to theName.
  798. void
  799. TArt::GetName(char* theName)
  800. {
  801.     char* pArtName=this->fArt.name;
  802.     while(*theName++=*pArtName++)
  803.         ;
  804. }
  805.  
  806. // ------------------------------------------------------------------------
  807. // TArt::Init
  808. // Initialize the art object.
  809. // Set it's PICT ID and drawing location.
  810. void
  811. TArt::Init(ArtType theArt)
  812. {
  813.         // Save art object description.
  814.     this->fArt = theArt;
  815.     this->fLastDepth = 1;
  816.     SetRect(&this->fDrawRect, 0, 0, 0, 0);
  817.         // Normalize PICT to desired drawing location.
  818.     PicHandle hPict = (PicHandle) GetResource('PICT', this->fArt.pictId);
  819.     if(hPict)
  820.     {
  821.                 // Get the original drawing rect.
  822.         this->fDrawRect = (**hPict).picFrame;
  823.                 // Normalize rect to 0,0 in case the artist didn't.
  824.         OffsetRect(&this->fDrawRect, -this->fDrawRect.left,
  825.                                         -this->fDrawRect.top);
  826.                 // Move rect to loc.
  827.         OffsetRect(&this->fDrawRect, this->fArt.locH, this->fArt.locV);
  828.     }
  829. };
  830.  
  831. // ------------------------------------------------------------------------
  832. void
  833. TArt::SetDrawRect(Rect* theRect)
  834. {
  835.     this->fDrawRect = *theRect;
  836. }
  837.  
  838. // =========================================================================
  839. // TBitMap
  840. // ------------------------------------------------------------------------
  841. TBitMap::TBitMap()                // constructor
  842. {
  843. };
  844.  
  845. // ------------------------------------------------------------------------
  846. TBitMap::~TBitMap()        // destructor
  847. {
  848. };
  849.  
  850. // =========================================================================
  851. // TBitMapBW-->TBitMap
  852. // ------------------------------------------------------------------------
  853. TBitMapBW::TBitMapBW()                // constructor
  854. {
  855.     this->fOffPort = nil;
  856. };
  857.  
  858. // ------------------------------------------------------------------------
  859. TBitMapBW::~TBitMapBW()        // destructor
  860. {
  861.     if(this->fOffPort)
  862.     {
  863.         ClosePort(this->fOffPort);
  864.         DisposPtr(this->fOffPort->portBits.baseAddr);
  865.         DisposPtr((Ptr)this->fOffPort);
  866.     }
  867. };
  868.  
  869. // ------------------------------------------------------------------------
  870. // TBitMapBW::CopyOffToOn
  871. // Copy all of off-screen port to on-screen port.
  872. void
  873. TBitMapBW::CopyOffToOn()
  874. {
  875.     this->CopyOffToOn(this->fOffRect);
  876. };
  877.  
  878. // ------------------------------------------------------------------------
  879. // TBitMapBW::CopyOffToOn
  880. // Copy a rect from off-screen port to on-screen port.
  881. void
  882. TBitMapBW::CopyOffToOn(Rect& rectToCopy)
  883. {
  884.     GrafPtr         onPort;
  885.     
  886.     GetPort(&onPort);
  887.     CopyBits(    &this->fOffPort->portBits,
  888.                 &onPort->portBits,
  889.                 &rectToCopy,
  890.                 &rectToCopy, srcCopy, nil);
  891. };
  892.  
  893. // ------------------------------------------------------------------------
  894. // TBitMapBW::CopyOnToOff
  895. // Copy all of on-screen port to off-screen port.
  896. void
  897. TBitMapBW::CopyOnToOff()
  898. {
  899.     this->CopyOnToOff(this->fOffRect);
  900. };
  901.  
  902. // ------------------------------------------------------------------------
  903. // TBitMapBW::CopyOnToOff
  904. // Copy a rect from on-screen port to off-screen port.
  905. void
  906. TBitMapBW::CopyOnToOff(Rect& rectToCopy)
  907. {
  908.     GrafPtr         onPort;
  909.     
  910.     GetPort(&onPort);
  911.     CopyBits(    &onPort->portBits,    
  912.                 &this->fOffPort->portBits,
  913.                 &rectToCopy,
  914.                 &rectToCopy, srcCopy, nil);
  915. };
  916.  
  917. // ------------------------------------------------------------------------
  918. // TBitMapBW::DoneDrawing
  919. void
  920. TBitMapBW::DoneDrawing()        
  921. {
  922.     SetPort(this->fSavedOnPort);
  923. }
  924.  
  925. // ------------------------------------------------------------------------
  926. // TBitMapBW::Init
  927. // Build bit map for an offscreen port equal to the current grafPort.
  928. OSErr
  929. TBitMapBW::Init()        
  930. {
  931.     OSErr        err;
  932.     Rect        offRect;
  933.     GrafPtr        onPort,
  934.                 newOffPort;
  935.  
  936.     GetPort(&onPort);
  937.             // Our off-screen rect exactly duplicates the on-screen rect.
  938.     offRect = onPort->portRect;
  939.             // Normalize off-screen rect.
  940.     OffsetRect(&offRect, -offRect.left, -offRect.top);
  941.     newOffPort = (GrafPtr) NewPtr(sizeof(GrafPort));
  942.     if((err=MemError())!=noErr)
  943.         return err;
  944.     OpenPort(newOffPort);
  945.     newOffPort->portRect = offRect;
  946.     newOffPort->portBits.bounds = offRect;
  947.     RectRgn(newOffPort->clipRgn, &offRect);
  948.     RectRgn(newOffPort->visRgn, &offRect);
  949.             // Rect is normalized so we only need to use its right and bottom.
  950.     newOffPort->portBits.rowBytes = ((offRect.right + 15) >> 4) << 1;
  951.     newOffPort->portBits.baseAddr = NewPtr(newOffPort->portBits.rowBytes * (long)offRect.bottom);
  952.     if((err=MemError())!=noErr) {
  953.         SetPort(onPort);
  954.         ClosePort(newOffPort);
  955.         DisposPtr((Ptr)newOffPort);
  956.         return err;
  957.         }
  958.             // Clear out new offScreen rect.
  959.     EraseRect(&offRect);
  960.             // Save key variables.
  961.     this->fOffRect = offRect;
  962.     this->fOffPort = newOffPort;
  963.             // Restore to screen port.
  964.     SetPort(onPort);
  965.     return noErr;
  966. };
  967.  
  968. // ------------------------------------------------------------------------
  969. // TBitMapBW::PrepareForDrawing
  970. // Set the port to this bit map and erase it.
  971. void
  972. TBitMapBW::PrepareForDrawing()        
  973. {
  974.     GetPort(&this->fSavedOnPort);
  975.     SetPort(this->fOffPort);
  976.     EraseRect(&this->fOffRect);
  977. }
  978.  
  979. // =========================================================================
  980. // TBitMapColor-->TBitMap
  981. // ------------------------------------------------------------------------
  982. TBitMapColor::TBitMapColor()        // constructor
  983. {
  984.     this->fOffGWorld = nil;
  985. };
  986.  
  987. // ------------------------------------------------------------------------
  988. TBitMapColor::~TBitMapColor()        // destructor
  989. {
  990.     if(this->fOffGWorld)
  991.     {
  992.         DisposeGWorld(this->fOffGWorld);
  993.     }
  994. };
  995.  
  996. // ------------------------------------------------------------------------
  997. // TBitMapColor::CopyOffToOn
  998. // Copy all of off-screen port to on-screen port.
  999. void
  1000. TBitMapColor::CopyOffToOn()
  1001. {
  1002.     this->CopyOffToOn(this->fOffRect);
  1003. };
  1004.  
  1005. // ------------------------------------------------------------------------
  1006. // TBitMapColor::CopyOffToOn
  1007. // Copy a rect from off-screen port to on-screen port.
  1008. void
  1009. TBitMapColor::CopyOffToOn(Rect& rectToCopy)
  1010. {
  1011.     CGrafPtr         onPort;
  1012.     GDHandle        onDevice;
  1013.     
  1014.     GetGWorld(&onPort, &onDevice);
  1015.     PixMapHandle hOffPixMap = GetGWorldPixMap(this->fOffGWorld);
  1016.      LockPixels(hOffPixMap);
  1017.     CopyBits(    &**(BitMap**)hOffPixMap,    
  1018.                 &**(BitMap**)onPort->portPixMap,
  1019.                 &rectToCopy,
  1020.                 &rectToCopy,
  1021.                 srcCopy, nil);
  1022.     UnlockPixels(hOffPixMap);
  1023. };
  1024.  
  1025. // ------------------------------------------------------------------------
  1026. // TBitMapColor::CopyOnToOff
  1027. // Copy all of on-screen port to off-screen port.
  1028. void
  1029. TBitMapColor::CopyOnToOff()
  1030. {
  1031.     this->CopyOnToOff(this->fOffRect);
  1032. };
  1033.  
  1034. // ------------------------------------------------------------------------
  1035. // TBitMapColor::CopyOnToOff
  1036. // Copy a rect from on-screen port to off-screen port.
  1037. void
  1038. TBitMapColor::CopyOnToOff(Rect& rectToCopy)
  1039. {
  1040.     CGrafPtr         onPort;
  1041.     GDHandle        onDevice;
  1042.     
  1043.     GetGWorld(&onPort, &onDevice);
  1044.     PixMapHandle hOffPixMap = GetGWorldPixMap(this->fOffGWorld);
  1045.      LockPixels(hOffPixMap);
  1046.     CopyBits(    &**(BitMap**)onPort->portPixMap,    
  1047.                 &**(BitMap**)hOffPixMap,
  1048.                 &rectToCopy,
  1049.                 &rectToCopy,
  1050.                 srcCopy, nil);
  1051.     UnlockPixels(hOffPixMap);
  1052. };
  1053.  
  1054. // ------------------------------------------------------------------------
  1055. // TBitMapColor::DoneDrawing
  1056. void
  1057. TBitMapColor::DoneDrawing()        
  1058. {
  1059.     UnlockPixels(GetGWorldPixMap(this->fOffGWorld));
  1060.     SetGWorld(this->fSavedOnPort, this->fSavedOnDevice);
  1061. }
  1062.  
  1063. // ------------------------------------------------------------------------
  1064. // TBitMapColor::Init
  1065. // Build bit map for an offscreen port equal to the current grafPort.
  1066. OSErr
  1067. TBitMapColor::Init()    
  1068. {
  1069.     short            pixelDepth=8;
  1070.     RGBColor        myRGBColor;
  1071.     CGrafPtr         onPort;
  1072.     GDHandle        onDevice;
  1073.     GWorldPtr        offGWorld;
  1074.     Rect            offRect;
  1075.  
  1076.     GetGWorld(&onPort, &onDevice);
  1077.     offRect = onPort->portRect;
  1078.             // Normalize off-screen rect.
  1079.     OffsetRect(&offRect, -offRect.left, -offRect.top);
  1080.             // we have created a world
  1081.     OSErr err = NewGWorld(&offGWorld, pixelDepth, &offRect, nil, nil, 0);
  1082.     if(err!=noErr)
  1083.         return err;
  1084.             // Everything from here on is done off screen.
  1085.     SetGWorld(offGWorld, nil);
  1086.             // set the background color to white
  1087.     myRGBColor.red = 0xFFFF;
  1088.     myRGBColor.blue = 0xFFFF;
  1089.     myRGBColor.green = 0xFFFF;
  1090.     RGBBackColor(&myRGBColor);
  1091.             // set the foreground color to black
  1092.     myRGBColor.red = 0;
  1093.     myRGBColor.blue = 0;
  1094.     myRGBColor.green = 0;
  1095.     RGBForeColor(&myRGBColor);
  1096.             // Clear out new offScreen rect.
  1097.     EraseRect(&offRect);
  1098.             // Save key variables.
  1099.     this->fOffRect = offRect;
  1100.     this->fOffGWorld = offGWorld;
  1101.             // Restore to on-screen GWorld.
  1102.     SetGWorld(onPort, onDevice);
  1103.     return noErr;
  1104. };
  1105.  
  1106. // ------------------------------------------------------------------------
  1107. // TBitMapColor::PrepareForDrawing
  1108. // Set the port to this bit map and erase it.
  1109. void
  1110. TBitMapColor::PrepareForDrawing()        
  1111. {
  1112.     GetGWorld(&this->fSavedOnPort, &this->fSavedOnDevice);
  1113.     SetGWorld(this->fOffGWorld, nil);
  1114.         // We ignore any failure of LockPixels.
  1115.     (void) LockPixels(GetGWorldPixMap(this->fOffGWorld));
  1116.     EraseRect(&this->fOffRect);
  1117. }
  1118.  
  1119.